﻿/*
 * CoordinateSystemLibrary
 * 
 * initial implementation : 20.11.2008
 *
 * Copyright (c) Adam Sida, asida@centrum.cz.
 * All rights reserved.
 * 
 * for license see Petra.Gis.License.txt
 */
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using Petra.Gis.ReferenceSystemServices;


namespace Petra.Gis
{
  /// <summary>
  /// represents Library with predefined coordinate systems
  /// </summary>
  [DataContract(Name = "SrsLibrary")]
  [KnownType(typeof(ProjectedCoordinateSystem))]
  [KnownType(typeof(GeocentricCoordinateSystem))]
  [KnownType(typeof(GeographicCoordinateSystem))]
  public class CoordinateSystemLibrary
  {

    protected List<CoordinateSystem> _cordinateSystems;




    /// <summary>
    /// xaml constructor
    /// </summary>
    public CoordinateSystemLibrary()
    {
      _cordinateSystems = new List<CoordinateSystem>();
    }






    /// <summary>
    /// stores predefined collection of Petra.Gis coordinate systems
    /// this colection might help with datasources, without coordinate system,
    /// where only coordinate system ID (eg. EPSG:2065) exists
    /// then this collection is searched for full coordinate system def;-)
    /// </summary>
    [DataMember(Name = "CrsList")]
    public List<CoordinateSystem> CoordinateSystems
    {
      get { return _cordinateSystems; }
      set
      {
        if (value == null)
          throw new ArgumentException("Coordinate systems can't be null");
        _cordinateSystems = value;
      }
    }






    ///// <summary>
    ///// search coordinate system by given parameters: authority name, code and storage units name
    ///// </summary>
    ///// <param name="authority">coordinate system authority name</param>
    ///// <param name="code">coordinate system code</param>
    ///// <param name="storageUnitName">name of storage units</param>
    ///// <returns>if any predefined coordinate system in cache meets search criteria
    ///// then first matching coordinate system is returned. If no match, returns null.
    ///// </returns>
    //public CoordinateSystem SearchBy(string authority, string code, string storageUnitName)
    //{

    //  //CoordinateSystem result = null;

    //  // search first in coordinate systems...
    //  CoordinateSystem cs = SearchBy(authority, code);
    //  if(cs !=null)
    //    return _resolveNamedCsStorageUnits(cs, storageUnitName);

    //  // ok, not found
    //  // try search in transforms collection...
    //  //foreach (SRSTransform t in SRSTransform.Transforms)
    //  //{
    //  //  if (t.Source.Metadata.Authority == authority && t.Source.Metadata.AuthorityCode.ToString() == code)
    //  //    //result =  t.Source;
    //  //    return _resolveNamedCsStorageUnits(t.Source, storageUnitName);

    //  //  else if (t.Target.Metadata.Authority == authority && t.Target.Metadata.AuthorityCode.ToString() == code)
    //  //    //result = t.Target;
    //  //    return _resolveNamedCsStorageUnits(t.Target, storageUnitName);
    //  //}

    //  // if coordinate system found
    //  // and units are specified as input parameter
    //  // try change coordinate system units
    //  //if (result != null && storageUnitName != "")
    //  //{
    //  //  // try resolve storage units..
    //  //  return resolveNamedCsStorageUnits(result, storageUnitName);
    //  //}

    //  return null;
    //}






    public CoordinateSystem SearchBy(string authority, string code)
    {
      foreach (CoordinateSystem cs in this.CoordinateSystems)
      {
        if (cs.Metadata.Authority == authority && cs.Metadata.AuthorityCode.ToString() == code)
          return cs;
      }
      return null;

    }




    /// <summary>
    /// Adds a list of coordinate systems into this library.
    /// </summary>
    /// <param name="anotherSRSList">IEnumerable list of CoordinateSystems</param>
    public void Add(IEnumerable<CoordinateSystem> anotherSRSList)
    { 
      CoordinateSystem tmp;

      foreach(CoordinateSystem cs in anotherSRSList)
      {
        tmp = this.SearchBy(cs.Metadata.Authority, cs.Metadata.AuthorityCode.ToString());
        if(!tmp.EqualParams(cs,CsCompareType.SkipStorageUnits))
          this.CoordinateSystems.Add(cs);
      }
    }





    ///// <summary>
    ///// if coordinate system found and storage unist differs from search request
    ///// coordinate system definition is updated by requested storage units
    ///// </summary>
    ///// <param name="cs">coordinate system to update</param>
    ///// <param name="inputStorageUnitName">name of storage units to replace original with</param>
    ///// <returns>updated coordinate system. If requested units not found or units are different (angular x distance) returns null</returns>
    //protected CoordinateSystem _resolveNamedCsStorageUnits(CoordinateSystem cs, string inputStorageUnitName)
    //{
    //  // if coordinate system found
    //  // and units are specified as input parameter
    //  if (inputStorageUnitName == "")
    //    return cs;

    //  // try change coordinate system units
    //  // try resolve storage units..
    //  // search for unit by given name
    //  MeasureUnit su = MeasureUnit.Parse(inputStorageUnitName);

    //  // if unit not found, return null
    //  if (su == null)
    //    return null;

    //  // if some unit found, check for sure
    //  // if type is same (angular or distance)
    //  if (cs.Unit.GetType() != su.GetType())
    //    return null;
    //  //throw new ArgumentException("specified coordinate system in:" + csInfo +
    //  //                            " has " + su.GetType().ToString() + " storage units  and " +
    //  //                            " found coordinate system has " + result.Unit.GetType().ToString());

    //  // if given unit is different from cs one
    //  // clone cs and replace
    //  if (!cs.Unit.EqualParams(su))
    //  {
    //    CoordinateSystem result = cs.Clone();
    //    result.Unit = su;
    //    return result;
    //  }
    //  else
    //    // or leave and return cs untouched
    //    return cs;

    //}


  }
}
